package com.example.usb.ai;

import android.graphics.Bitmap;

import com.baidu.aip.util.Base64Util;
import com.example.usb.dao.entity.PhotoPicBean;
import com.lib.uvccamera.utils.DebugLog;
import com.lib.uvccamera.utils.FileUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * created by liangkun on ${DATA}
 * Describe: 人脸处理标准
 */

public class FaceStandardUtil {
    // 默认笑脸评分算法常量
    public static final Integer DEF_DIV_SCALE = 2;
    public static final Double DEF_DIV_DIVISOR_POINT = 0.50d;
    public static final Double DEF_DIV_DIVISOR_ZERO = 0.00d;
    public static final Double DEF_DIV_DIVISOR_THREE = 3.00d;
    public static final Double DEF_DIV_DIVISOR_FIVE = 5.00d;
    public static final Double DEF_DIV_DIVISOR_TWENTYFIVE = 25.00d;
    public static final Double DEF_DIV_DIVISOR_TWENTYTWO = 22.00d;
    public static final Double DEF_DIV_DIVISOR_FIFTEEN = 15.00d;
    public static final Double DEF_DIV_DIVISOR_TEN = 10.00d;
    public static final Double DEF_DIV_DIVISOR_TWENTY = 20.00d;
    public static final Double DEF_DIV_DIVISOR_THIRTY = 30.00d;
    public static final Double DEF_DIV_DIVISOR_150 = 150.00d;
    public static final Double DEF_DIV_DIVISOR_240 = 240.00d;
    public static final Double DEF_DIV_DIVISOR_120 = 120.00d;
    public static final Double DEF_DIV_DIVISOR_300 = 90000.00d; //人脸长宽被除数
    public static final Double DEF_DIV_DIVISOR_75 = 5625.00d; //人脸长宽限制条件
    public static final int DEF_EXPRESSION_SMILE = 1; //表情，0，不笑；1，微笑；2，大笑。face_fields包含expression时返回

    /**
     * 根据模糊度，三维度，完整度，大小来是否注册人脸
     *
     * @param aiBean 人脸信息
     * @return boolean
     */
    public static boolean isRegisterFace(AiV3Bean.FaceList aiBean) {
        AiV3Bean.FaceList.Location location = aiBean.getLocation();
        AiV3Bean.FaceList.Angle angle = aiBean.getAngle();
        AiV3Bean.FaceList.Quality quality = aiBean.getQuality();
        //左右三维
        boolean isYawLh20 = Math.abs(angle.getYaw()) <= 20;
        //上下俯仰
        boolean isPitchLh20 = Math.abs(angle.getPitch()) <= 15;
        //模糊度范围	blur，取值范围[0~1]，0是最清晰，1是最模糊	小于0.7
        boolean isBlur = quality.getBlur() < 0.5d;
        //人脸完整度ompleteness（0或1），0为人脸溢出图像边界，1为人脸都在图像边界内
        boolean isCompleteness = quality.getCompleteness() == 1;
        //是否为人脸
        boolean isHuman = aiBean.getFaceProbability() >= 0.6d;
        //是否光照
        boolean isIllumination = quality.getIllumination() >= 40;
        //遮挡比例
        AiV3Bean.FaceList.Quality.Occlusion occlusion = quality.getOcclusion();
        boolean isChin = occlusion.getChinContour() <= 0.5d;
        boolean isRightCheek = occlusion.getRightCheek() <= 0.7d;
        boolean isLeftCheek = occlusion.getLeftCheek() <= 0.7d;
        boolean isMouth = occlusion.getMouth() <= 0.6d;
        boolean isNose = occlusion.getNose() <= 0.6d;
        boolean isRightEye = occlusion.getRightEye() <= 0.5d;
        boolean isLeftEye = occlusion.getLeftEye() <= 0.5d;
//        //人脸长宽 人脸部分不小于100*100像素
        boolean isWidth = location.getWidth() * location.getHeight() > DEF_DIV_DIVISOR_75;
        return isYawLh20 && isPitchLh20 && isBlur && isCompleteness && isHuman && isIllumination
                && isChin && isRightCheek && isLeftCheek && isMouth && isNose && isRightEye && isLeftEye && isWidth;
    }

    /**
     * 根据模糊度，三维度，完整度，大小来是否注册人脸
     * 满分100.00分 小数点2位
     *
     * @param aiBean 人脸信息
     * @return boolean
     */
    public static double getFaceScore(AiV3Bean.FaceList aiBean) {
        AiV3Bean.FaceList.Location location = aiBean.getLocation();
        AiV3Bean.FaceList.Angle angle = aiBean.getAngle();
        AiV3Bean.FaceList.Quality quality = aiBean.getQuality();

//        DebugLog.d(DebugLog.LOGHsc + " 人脸打分 qualityResult " + qualityResult.toString());
        //左右三维 【10分】
        Double leftright = getDivideMulScore(Math.abs(angle.getYaw()), DEF_DIV_DIVISOR_TWENTY, DEF_DIV_DIVISOR_TEN);
        //上下俯仰 【10分】
        Double updown = getDivideMulScore(Math.abs(angle.getPitch()), DEF_DIV_DIVISOR_FIFTEEN, DEF_DIV_DIVISOR_TEN);
        //模糊度范围 【20分】 	blur，取值范围[0~1]，0是最清晰，1是最模糊	小于0.7
        Double blur = getDivideMulScore(quality.getBlur(), DEF_DIV_DIVISOR_POINT, DEF_DIV_DIVISOR_TWENTY);
        //是否光照 【5分】
        Double sun = (double) quality.getIllumination();
        Double sunTwo = sun > DEF_DIV_DIVISOR_120 ? (DEF_DIV_DIVISOR_240 - sun) : sun;
        Double lumination = getDivideScore(sunTwo, DEF_DIV_DIVISOR_120, DEF_DIV_DIVISOR_FIVE);
        //人脸宽高 【10分】
        Double widthHeight = (double) (location.getWidth() * location.getHeight());
        Double width = widthHeight >= DEF_DIV_DIVISOR_300 ? DEF_DIV_DIVISOR_300 : widthHeight;
        Double realWidth = getDivideScore(width, DEF_DIV_DIVISOR_300, DEF_DIV_DIVISOR_TEN);
        //人脸旋转角度 【15分】
        int abs = (int) Math.abs(location.getRotation());
        Double rotation = abs > DEF_DIV_DIVISOR_TWENTYFIVE ? DEF_DIV_DIVISOR_TWENTYFIVE : abs;
        Double rotationScore = getDivideMulScore(rotation, DEF_DIV_DIVISOR_TWENTYFIVE, DEF_DIV_DIVISOR_FIFTEEN);
        //笑脸分数【3分】
        boolean smile = aiBean.getExpression().getType().equals("smile");
        Double expression = smile ? DEF_DIV_DIVISOR_THREE : DEF_DIV_DIVISOR_ZERO;
        //两两计算
        Double leftUp = add(leftright, updown);
        Double blurLumination = add(blur, lumination);
        Double widthRotation = add(realWidth, rotationScore);
        //最后相加
        Double realStore = add(add(add(add(expression, leftUp), blurLumination), widthRotation), DEF_DIV_DIVISOR_TWENTYTWO);
        DebugLog.d(DebugLog.LOGHsc + " 人脸打分  " + realStore + " 左右三维 " + leftright + " 上下俯仰 " + updown +
                " 模糊度 " + blur + " 光照 " + lumination + " 宽高分 " + realWidth + " 偏转分 " + rotationScore + " 笑脸分数 " + expression);
        return realStore;
    }

    /**
     * 返回人脸评分分数
     *
     * @param abs        原值
     * @param divisor    被除数
     * @param multiplier 被乘数
     * @return 分数
     */
    private static double getDivideMulScore(double abs, double divisor, double multiplier) {
        Double socre = divide(divisor - abs, divisor, DEF_DIV_SCALE);
        Double socreReal = mul(socre, multiplier);
        return socreReal;
    }

    /**
     * 返回人脸评分分数
     *
     * @param abs        原值
     * @param divisor    被除数
     * @param multiplier 被乘数
     * @return 分数
     */
    private static double getDivideScore(double abs, double divisor, double multiplier) {
        Double socre = divide(abs, divisor, DEF_DIV_SCALE);
        Double socreReal = mul(socre, multiplier);
        return socreReal;
    }

    /**
     * * 提供（相对）精确的除法运算。 当发生除不尽的情况时，由scale参数指定精度，以后的数字四舍五入。
     *
     * @param dividend 被除数
     * @param divisor  除数
     * @param scale    表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    private   static Double divide(Double dividend, Double divisor, Integer scale) {
//        if (dividend == DEF_DIV_DIVISOR_ZERO) {
////            return divisor;
////        }
        BigDecimal b1 = new BigDecimal(Double.toString(dividend));
        BigDecimal b2 = new BigDecimal(Double.toString(divisor));
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 提供精确的加法运算。
     *
     * @param value1 被加数
     * @param value2 加数
     * @return 两个参数的和
     */
    public static Double add(Double value1, Double value2) {
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param value1 被减数
     * @param value2 减数
     * @return 两个参数的差
     */
    public static double sub(Double value1, Double value2) {
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param value1 被乘数
     * @param value2 乘数
     * @return 两个参数的积
     */
    public static Double mul(Double value1, Double value2) {
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.multiply(b2).doubleValue();
    }


    /**
     * 裁剪的人头检测是否多于一个人头
     *
     * @param path
     */
    public  boolean isMoreThanOne(String path) {
        byte[] userByte = new byte[0];
        try {
            userByte = FileUtils.readFileByBytes(path);
            //人脸检测
            AiV3Bean aiBean = AiLibManager.getInstance().detectFace(Base64Util.encode(userByte));
            if (aiBean.getResult() != null && aiBean.getResult().getFaceList().size() > 1) {

                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }
}
